package com.seestech.sell.common.config.schedule;


import com.seestech.sell.common.config.ApplicationConfig;
import com.seestech.sell.common.config.SpringUtil;
import com.seestech.sell.common.threads.LogFileThread;
import com.seestech.sell.common.utils.Constants;
import com.seestech.sell.common.utils.DateUtils;
import com.seestech.sell.common.utils.FileUtils;
import com.seestech.sell.domain.mapper.*;
import com.seestech.sell.domain.model.*;
import com.seestech.sell.domain.model.enums.StatusEnums;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static com.seestech.sell.common.utils.DateUtils.diffMinutes;


/**
 * @description  定时任务 跑终端在线情况
 * Created by idiot on 2017/3/8.
 */
@Configuration
@EnableScheduling
public class SchedulingConfig {
    private static Logger logger = LoggerFactory.getLogger(SchedulingConfig.class);

    private IAgentDao agentDao = null;
    private IOrderDao orderDao = null;
    private IShelfDao shelfDao = null;
    private IRecorderDao recorderDao = null;
    private IPublishHistoryDao publishHistoryDao = null;
    private ILogDao logDao = null;
    private IReportDao reportDao = null;
    private IScreenshotsDao screenshotsDao = null;
    private IAgentTaskDao agentTaskDao = null;
    private ApplicationConfig applicationConfig = null;


    /**
     * 从0分钟后开始  每5分钟执行一次
     * 更新终端在线情况
     */
    @Scheduled(cron = "0 1/5 * * * ?")
    public void updateAgentOnlineStatus(){
        logger.info("===================>开始执行定时任务【更新终端在线情况】");
        if(agentDao == null){
            agentDao = (IAgentDao) SpringUtil.getBean("IAgentDao");
        }
        //把时间 转换为天数   更新终端在线状态
        int day;
        long minutes;     //默认
        String currentDate = DateUtils.format(new Date(), DateUtils.SDF_YMD_PATTERN);
        boolean flag;   // 是否计算分钟数
        logger.info("现在时间："+ currentDate);
        //获取所有有效的终端信息
        List<Agent> list = agentDao.getAllValidAgents();
        for (Agent agent : list){
            //先判断当前终端的心跳频率是否大于5  并且处于在线状态  如果大于5就不用执行下去了(原因：心跳频率不足5的若继续执行可能会更新在线状态为断线)
            if(agent.getOnlineStatus() == 0 && agent.getBeatFrequency() > Constants.Regular.agent_live_minutes){
                continue;
            }
            flag = true;    //初始化
            day = 0; minutes = 0;
            //获取系统当前时间  对比终端上一次心跳时间  转换为分钟数  更新终端心跳频率
            if(agent.getLastHeartBeatTime() != null){
                logger.info("终端上次心跳时间："+ DateUtils.format(agent.getLastHeartBeatTime(), DateUtils.SIMPLE_DATE_HOURS_PATTERN));
                String nextDay = DateUtils.getNextDayTime(agent.getLastHeartBeatTime(), DateUtils.SDF_YMD_PATTERN);
                // 上次心跳时间获取第二天时间  如果年月日匹配当前时间  就断线一天  不匹配就计算分钟数
                if (currentDate.equals(nextDay)){
                    day = -1;    //断线一天
                    flag = false;   //不计算分钟数
                }
                minutes = diffMinutes(new Date(), agent.getLastHeartBeatTime());
            }else {
                minutes = diffMinutes(new Date(), agent.getCreateTime());
            }
            logger.info("终端【"+ agent.getAgentName() +"】心跳频率："+ minutes);

            //如果分钟数 大于5分钟  小于24小时  则断线1天  对于大于一天的 向上取整
            if (flag && minutes > Constants.Regular.agent_live_minutes){
                day = minutes < (60*24) ? 1 :(int) Math.ceil(minutes / 60f / 24.0);
            }
            Agent info = new Agent();
            info.setAgentId(agent.getAgentId());        //设置agentId
            info.setOnlineStatus(day);                  //修改在线天数
            logger.info("终端【"+ agent.getAgentName() +"】--断线天数：" + day);
            if(agentDao.update(info) < 1){
                logger.error("更新终端【"+ agent.getAgentName() +"】属性【心跳频率 终端在线状态】失败");
            }
        }
        logger.info("===================>执行定时任务【更新终端在线情况】完成");
    }


    /**
     * 处理订单信息
     * 每天晚上23点50分   执行
     */
    @Scheduled(cron = "0 50 23 * * ?")
    public void execOrder(){
        logger.info("===================>执行定时任务【更新订单状态】开始");
        if(orderDao == null){
            orderDao = (IOrderDao) SpringUtil.getBean("IOrderDao");
        }
        //获取处理中的有效订单信息
        Order info = new Order();
        info.setSuccess(0);     //处理中的订单
        info.setStatus(StatusEnums.VALID.getValue());   //有效
        List<Order> list = orderDao.getOrdersByOrder(info);
        //遍历这些订单信息
        for (Order item : list){
            //获取订单创建时间   比对  当前时间   相差超过10分钟的就修改为无效
            if(item.getCreateTime() != null) {
                long minutes = DateUtils.diffMilliseconds(item.getCreateTime(), new Date());
                if(minutes > 10){
                    item.setStatus(StatusEnums.INVALID.getValue()); //无效
                    if(orderDao.update(item) < 1){
                        logger.error("修改订单状态为无效失败");
                    }
                }
            }
        }
        logger.info("===================>执行定时任务【更新订单状态】开始");
    }


    /**
     * 定时更新终端库存状态
     * 从0分钟后开始  每10分钟执行一次
     */
    @Scheduled(cron = "0 0/10 * * * ?")
    public void updateAgentStock(){
        logger.info("===================>执行定时任务【更新终端库存状态】开始");
        //判断agentDao是否为null
        if(agentDao == null){
            agentDao = (IAgentDao) SpringUtil.getBean("IAgentDao");
        }
        if(shelfDao == null) {
            shelfDao = (IShelfDao) SpringUtil.getBean("IShelfDao");
        }
        if(recorderDao == null){
            recorderDao = (IRecorderDao) SpringUtil.getBean("IRecorderDao");
        }
        boolean flag = false;   //是否修改终端库存告警信息
        //获取所有有效的终端信息
        List<Agent> agents = agentDao.getAllValidAgents();
        if(agents != null && agents.size() > 0){
            logger.info("===========>>>>>开始进入修改终端库存告警信息...........");
            for (Agent agent : agents){
                //根据agentId获取货架信息  获取商品的对应告警数量  以及商品编号信息
                Shelf shelf = shelfDao.getShelfByShelfId(agent.getShelfId());

                //当终端没有绑定货架时  跳过该条数据
                if (shelf == null){
                    continue;
                }
                //如果当前货架没有告警数量  或者产品
                if(shelf.getAlarms() == null || "".equals(shelf.getAlarms()) || "".equals(shelf.getProducts()) || shelf.getProducts() == null){
                    continue;
                }
                String[] alarms = shelf.getAlarms().split(";");
                String[] products = shelf.getProducts().split(";");
                //遍历商品编号   
                for (int i = 0; i < products.length; i++) {
                    //获取该货架最新的剩余库存信息
                    List<Recorder> recorders = recorderDao.getRecordersByIds(agent.getAgentId(), shelf.getShelfId(), Long.parseLong(products[i]));
                    //当记录存在时
                    if(recorders != null && recorders.size() > 0){
                        Recorder info = recorders.get(0);       //获取最新的库存记录信息  拿到剩余的库存
                        String[] remains = info.getRemain().split(";");
                        //当剩余库存小于等于商品告警库存时
                        if(Integer.parseInt(remains[i]) <= Integer.parseInt(alarms[i])){
                            logger.info("终端【"+agent.getAgentName()+"】库存告警====>>>"+remains[i]+"/"+alarms[i]);
                            flag = true;
                            break;
                        }else {
                            if(agent.getLess() != 0) {
                                //库存充足   修改告警信息  ===>  不告警状态
                                logger.info("终端【" + agent.getAgentName() + "】======>>>解除库存告警信息.........");
                                updateLess(agent, 0);
                            }
                            flag = false;       //防止上一次的数据影响
                            break;
                        }
                    }else {
                        //不存在记录  说明没有补货  初始状态下  库存为0
                        logger.info("终端【"+agent.getAgentName()+"】库存告警====>>>");
                        flag = true;
                        break;
                    }
                }
                //修改终端库存告警
                if(flag){
                    logger.info("终端【"+ agent.getAgentName()+"】======>>>更新库存告警.........");
                    //库存告警
                    updateLess(agent, 1);
                }
            }
        }
        logger.info("===================>执行定时任务【更新终端库存状态】结束");
    }


    /**
     * 清理发布历史任务  每20小时清理一次
     */
    @Scheduled(cron = "0 0 0/20 * * ?")
    public void cleanPublishHistory(){
        logger.info("=======>>>>清理发布历史任务=======>>>>>【开始】");
        if(publishHistoryDao == null)
            publishHistoryDao = (IPublishHistoryDao) SpringUtil.getBean("IPublishHistoryDao");
        PublishHistory info = new PublishHistory();
        info.setStatus(StatusEnums.VALID.getValue());
        List<PublishHistory> list = publishHistoryDao.getPublishHistoriesByInfo(info);
        for (PublishHistory history : list){
            //下发状态为空  或者 0  并且 创建时间大于七天
            if(history.getPublishStatus() == null || history.getPublishStatus().equals(0)){
                if(history.getCreateTime() != null) {
                    long minutes = diffMinutes(new Date(), history.getCreateTime());
                    if(minutes >= 60*24*7){
                        logger.info("=======>>>>清理发布历史任务===【"+history.getPublishName()+"】====>>>>>准备清理中");
                        history.setStatus(StatusEnums.INVALID.getValue());
                        history.setUpdateTime(new Date());
                        if(publishHistoryDao.update(history) < 1){
                            logger.error("=======>>>>清理发布历史任务=======>>>>>修改发布历史信息失败......");
                        }
                    }
                }
            }
        }
        logger.info("=======>>>>清理发布历史任务=======>>>>>【结束】");
    }


    //清理日志信息   一天一次   清理  超过一周的日志信息
    @Scheduled(cron = "0 0 23 * * ?")
    public void cleanLog(){
        logger.info("=======>>>>清理日志信息任务=======>>>>>【开始】");
        if (logDao == null)
            logDao = (ILogDao) SpringUtil.getBean("ILogDao");
        Log info = new Log();
        List<Log> list = logDao.getAllLogs(new RowBounds(0, Integer.MAX_VALUE), info);
        //待删除的日志集合
        Long[] ids = new Long[list.size()];
        long minute = 0;
        for (int i = 0; i < list.size(); i ++){
            Log log = list.get(i);
            if (log.getCreateTime() != null) {
                minute = DateUtils.diffMinutes(new Date(), log.getCreateTime());
                if(minute > 60*24*7){
                    ids[i] = log.getLogId();
                    //添加数据到线程队列
                    LogFileThread.addLogFile(log.toString());
                }
            }else {
                ids[i] = log.getLogId();
                //添加数据到线程队列
                LogFileThread.addLogFile(log.toString());
            }
        }
        if(ids != null && ids.length > 0)
            logDao.deleteBatch(ids);
        logger.info("=======>>>>清理日志信息任务=======>>>>>【结束】");
    }


    //清理日志信息   一天一次   清理  超过一周的日志信息
    @Scheduled(cron = "0 30 23 * * ?")
    public void cleanReportLog(){
        logger.info("=======>>>>清理反馈日志信息任务=======>>>>>【开始】");
        if (reportDao == null)
            reportDao = (IReportDao) SpringUtil.getBean("IReportDao");
        Report info = new Report();
        List<Report> list = reportDao.getAllReports(new RowBounds(0, Integer.MAX_VALUE), info);
        //待删除的日志集合
        Long[] ids = new Long[list.size()];
        long minute = 0;
        for (int i = 0; i < list.size(); i ++){
            Report report = list.get(i);
            if (report.getCreateTime() != null) {
                minute = DateUtils.diffMinutes(new Date(), report.getCreateTime());
                if(minute > 60*24*7){
                    ids[i] = report.getId();
                    //添加数据到线程队列
                    LogFileThread.addLogFile(report.toString());
                }
            }else {
                ids[i] = report.getId();
                //添加数据到线程队列
                LogFileThread.addLogFile(report.toString());
            }
        }
        if(ids != null && ids.length > 0)
            reportDao.deleteBatch(ids);
        logger.info("=======>>>>清理反馈日志信息任务=======>>>>>【结束】");
    }


    //清理终端截图信息   一天一次   清理  每台终端超过最新的20条信息  以及  图片
    @Scheduled(cron = "0 0 22 * * ?")
    public void clearScreenShots(){
        logger.info("定时任务=====>>批量删除截图信息与文件====>>【开始】");
        //获取截图信息
        if(screenshotsDao == null)
            screenshotsDao = (IScreenshotsDao) SpringUtil.getBean("IScreenshotsDao");
        if(applicationConfig == null)
            applicationConfig = (ApplicationConfig) SpringUtil.getBean("ApplicationConfig");
        if(agentDao == null)
            agentDao = (IAgentDao) SpringUtil.getBean("IAgentDao");
        //获取有效的终端信息
        List<Agent> agents = agentDao.getAllValidAgents();
        if(agents != null && agents.size() > 0){
            //遍历终端信息   获取对应的终端截图信息
            for (Agent agent : agents){
                List<Screenshots> screenshotses = screenshotsDao.getScreenshotsByAgentCode(new RowBounds(20, 100), agent.getAgentCode());
                if(screenshotses != null && screenshotses.size() > 0){
                    Long[] ids = new Long[screenshotses.size()];
                    int i = 0;
                    for (Screenshots item : screenshotses){
                        //获取图片名  图片路径   删除图片文件
                        String filePath = FileUtils.addPathSeparate(applicationConfig.getBaseDirectory(), Constants.Regular.monitor_wall, agent.getAgentCode(), item.getImageName());
                        FileUtils.deleteFile(new File(FileUtils.getTrulyPath(FileUtils.getWindowsPath(filePath))));
                        //获取截图的编号  加入集合   以便于删除
                        ids[i] = item.getScreenshotsId();
                        i++;
                    }
                    if(screenshotsDao.deleteBatch(ids) < 1){
                        logger.error("定时任务=====>>批量删除截图信息与文件====>>【失败】");
                    }
                }
            }
        }
        logger.info("定时任务=====>>批量删除截图信息与文件====>>【结束】");
    }

    //清理终端任务信息记录    一天一次   清理
    @Scheduled(cron = "0 30 22 * * ?")
    public void clearAgentTasks(){
        logger.info("定时任务=====>>清理终端任务信息记录====>>【开始】");
        //获取终端任务信息
        if(agentTaskDao == null)
            agentTaskDao = (IAgentTaskDao) SpringUtil.getBean("IAgentTaskDao");
        if(agentDao == null)
            agentDao = (IAgentDao) SpringUtil.getBean("IAgentDao");
        //获取有效的终端信息
        List<Agent> agents = agentDao.getAllValidAgents();
        if(agents != null && agents.size() > 0){
            //遍历终端信息   获取对应的终端截图信息
            for (Agent agent : agents){
                List<AgentTaskInfo> agentTaskInfos = agentTaskDao.getAgentTasksByAgentCode(agent.getAgentCode());
                if (!agentTaskInfos.isEmpty()){
                    Long[] ids = new Long[agentTaskInfos.size()];
                    int i = 0;
                    //遍历集合   判断这个任务是否已经失效
                    for (AgentTaskInfo agentTaskInfo : agentTaskInfos){
                        if (StatusEnums.INVALID.getValue().equals(agentTaskInfo.getStatus())){
                            ids[i] = agentTaskInfo.getTaskId();
                            i++;
                        }
                    }
                    if (agentTaskDao.deleteBatch(ids) < 1){
                        logger.info("定时任务=====>>清理终端任务信息记录====>>【失败】");
                    }
                }
            }
        }
        logger.info("定时任务=====>>清理终端任务信息记录====>>【结束】");
    }


    /*********************   私有方法   *********************/

    //更新库存告警信息
    private void updateLess(Agent agent, int less){
        Agent info = new Agent();
        info.setAgentId(agent.getAgentId());
        info.setLess(less);   //库存状态
        info.setUpdateTime(new Date());    //设置修改时间
        if(agentDao.update(info) < 1){
            logger.error("===================>修改终端库存告警信息失败。。。。。。");
        }
    }
}
